import { Body, Controller, Delete, Param, ParseIntPipe, Post, Put, Req, UploadedFile, UseInterceptors } from '@nestjs/common';
import { BaseController } from '../base/base.controller';
import { UploadService } from 'apps/common/src/upload/upload.service';
import { FileInterceptor } from '@nestjs/platform-express';
import { DtoPipe } from '../pipes/dto/dto.pipe';
import { AddFirmwareDto, DevicePageDto, FirmwarePageDto, PageDto, UpdateFirmwareDto, UpgradeDto } from './dto';
import { DbService } from '@app/db';
import { Firmware } from '@app/db/entities/Firmware';
import { FindOptionsWhere, In } from 'typeorm';
import { OtaService } from './ota.service';
import { OtaTask } from '@app/db/entities/OtaTask';
import { OtaDevice } from '@app/db/entities/OtaDevice';

@Controller('ota')
export class OtaController extends BaseController {
    constructor(
        private readonly db:DbService,
        private readonly upload:UploadService,
        private readonly service:OtaService
    ){
        super()
    }

    @Post('upload/firmware')
    @UseInterceptors(FileInterceptor('firmware'))
    async updateInfo(@UploadedFile() firmware: Express.Multer.File, @Req() { memberId }) {
        const fileName = await this.upload.put(firmware, 'firmware' + memberId)
        return this.successRes(fileName)
    }

    @Post('firmware/page')
    async firmwarePage(@Body(new DtoPipe({skipMissingProperties : false})) dto:FirmwarePageDto) {
        let result:PaginationResult<Firmware> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<Firmware> = {
            
        }

        if(dto.name) {
            where.name = dto.name
        }

        
        result.total = await this.db.firmware.count(where)

        if(result.total > 0) {
            result.rows = await this.db.firmware.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})

        }
        
        return this.successRes(result)
    }

    @Post('add/firmware')
    async addFirmware(@Body(new DtoPipe({skipMissingProperties : false})) dto:AddFirmwareDto) {
        const r = await this.db.firmware.insert({...dto, createTime : this.utils.time()})
        return this.successRes()
    }

    @Put('update/firmware/:id')
    async update(@Body(new DtoPipe({skipNullProperties : true})) dto:UpdateFirmwareDto, @Param('id', ParseIntPipe) id:number) {
        if(id <= 0) return

        let fields = Object.keys(dto) as (keyof Firmware)[]
        if(fields.length == 0) return
        const station = await this.db.firmware.findOne({id : id}, fields)
       

        let updateData:KeyToValueType<Firmware> = {}
        for(let k in station) {
            if(k in dto && station[k] != dto[k]) {
                updateData[k] = dto[k]
            }
        }

        if(Object.keys(updateData).length == 0) return this.successRes()

        const res = await this.db.firmware.update({id : id}, updateData)
        if(res === 0) return this.failRes()

        return this.successRes()
    }

    @Delete('delete/firmware/:id')
    async del(@Param('id', ParseIntPipe) id:number, @Req() { member }) {
        if(id <= 0) return
        const firmware = await this.db.firmware.findOne({id}, ['file'])
        if(!firmware) return
        const r = await this.db.firmware.delete({id : id})
        if(r == 0) {
            return this.failRes()
        }else {
            this.upload.delFile(firmware.file)
            return this.successRes()
        }

    }

    @Post('upgrade')
    async upgrade(@Body(new DtoPipe({skipMissingProperties : false})) dto:UpgradeDto) {
        this.service.upgrade(dto)
    }

    @Post('upgrade/page')
    async upgradePage(@Body(new DtoPipe({skipMissingProperties : false})) dto:PageDto) {
        let result:PaginationResult<OtaTask & {firmwareName?:string}> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<OtaTask> = {
            
        }

        result.total = await this.db.otaTask.count(where)

        if(result.total > 0) {
            result.rows = await this.db.otaTask.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})

            const firmwareIds:number[] = []
            result.rows.forEach(row => {
                if(!firmwareIds.includes(row.firmware)) {
                    firmwareIds.push(row.firmware)
                }
            })

            const firmwares = await this.db.firmware.find({id : In(firmwareIds)}, ['chargeType', 'name', 'id'])
            result.rows.forEach(row => {
                const f = firmwares.find(item => item.id == row.firmware)
                row.firmwareName = f.name
            })

        }
        
        return this.successRes(result)
    }

    @Post('upgrade/device/page')
    async upgradeDevicePage(@Body(new DtoPipe({skipMissingProperties : false})) dto:DevicePageDto) {
        let result:PaginationResult<OtaDevice> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<OtaDevice> = {
            taskId : dto.task
        }

        if(dto.deviceId) {
            where.deviceId = dto.deviceId
        }

        result.total = await this.db.otaDevice.count(where)

        if(result.total > 0) {
            result.rows = await this.db.otaDevice.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})
        }
        
        return this.successRes(result)
    }
}
